package com.niuxuliang.activity.modules.processinstance;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import com.niuxuliang.activity.common.R;
import com.niuxuliang.activity.entity.FlowUtils;
import com.niuxuliang.activity.entity.WorkFlowEntity;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.*;

/**
 * 流程实例管理
 *
 * @author xl.niu
 */
@Slf4j
@RestController
@RequestMapping("/flow")
public class ProcessInstanceController {

    @Autowired
    private TaskService taskService;//任务管理
    @Autowired
    private RuntimeService runtimeService;//执行管理，包括启动、推进、删除流程实例等操作
    @Autowired
    private HistoryService historyService;//历史管理(执行完的数据的管理)
    @Autowired
    FlowUtils flowUtils;

    /**
     * 发起流程
     * <p>
     * act_hi_actinst       已完成的活动信息
     * act_hi_identitylink  参与者信息
     * act_hi_taskinst      任务表
     * act_hi_procinst      流程实例
     * act_ru_execution     执行表
     * act_ru_identitylink  参与者信息
     * act_ru_task          任务
     *
     * @return
     */
    @GetMapping("/start")
    public R startProcess(WorkFlowEntity entity) {
        HashMap<String, Object> variables = new HashMap<>();
        variables.put("assigness1", "zhangsan");
        variables.put("assigness2", "lisi");
        variables.put("assigness3", "wangwu");

        //第一个参数：流程定义key
        //第二个参数：业务标识
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess_1", "业务ID", variables);

        log.info("流程部署Id：" + processInstance.getDeploymentId());
        log.info("流程定义Id：" + processInstance.getProcessDefinitionId());
        log.info("流程实例Id：" + processInstance.getId());
        log.info("流程活动Id：" + processInstance.getActivityId());
        log.info("业务标识：" + processInstance.getBusinessKey());

        //验证是否启动成功
        //通过查询正在运行的流程实例来判断
        ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();

        //根据流程实例ID来查询
        List<ProcessInstance> runningList = processInstanceQuery.processInstanceId(processInstance.getProcessInstanceId()).list();
        log.debug("====start process processInstance====" + runningList);

        String processInstanceId = processInstance.getId();//流程实例ID

        //设置处理人
        /*Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        if (task != null) {
            //自动完成第一步
            Map<String, Object> map = new HashMap<String, Object>(2);
            map.put("check", 1);
            map.put("personId", "zq0788");
            taskService.setAssignee(task.getId(), "0000");
            taskService.complete(task.getId(), map);

            task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
            taskService.setAssignee(task.getId(), "0001");
        }*/

        HashMap<String, Object> res = new HashMap<>();
        res.put("流程实例ID", processInstance.getId());
        res.put("流程定义ID", processInstance.getProcessDefinitionId());

        return R.ok(res);
    }


    /**
     * 完成任务
     *
     * @param processInstanceId 流程ID
     * @param taskId            任务ID
     * @param toAssignee        办理人
     * @return
     */
    @GetMapping("/completeTask")
    public R completeTask(String processInstanceId, String taskId, String toAssignee) {
        taskService.complete(taskId);
        log.info("完成任务：任务ID：" + taskId);

        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        if (ObjectUtil.isNotNull(task))
            taskService.setAssignee(task.getId(), toAssignee);
        return R.ok("完成任务：任务ID：" + taskId);
    }

    /**
     * 查询流程状态（正在执行 or 已经执行结束）
     *
     * @param processInstanceId 流程实例ID
     */
    @GetMapping("/processState")
    public R processState(String processInstanceId) {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery() // 创建流程实例查询
                .processInstanceId(processInstanceId) // 用流程实例ID查询
                .singleResult();
        if (pi != null) {
            return R.ok("流程正在执行！").put("ProcessInstance", pi);
        } else {
            return R.ok("流程已经执行结束！");
        }
    }

    /**
     * 历史任务查询（已完成）
     *
     * @param processInstanceId 流程实例ID
     */
    @GetMapping("/historyFinishTaskList")
    public R historyFinishTaskList(String processInstanceId) {
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery() // 创建历史活动实例查询
                .processInstanceId(processInstanceId) // 流程实例ID
                .orderByTaskCreateTime()
                .asc()
                .finished() // 查询已经完成的任务
                .list();

        List<Map<String, Object>> res = new ArrayList<>();
        for (HistoricTaskInstance his : list) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("任务ID:", his.getId());
            map.put("流程实例ID:", his.getProcessInstanceId());
            map.put("任务名称：", his.getName());
            map.put("办理人：", his.getAssignee());
            map.put("开始时间：", DateUtil.formatDateTime(his.getStartTime()));
            map.put("结束时间：", DateUtil.formatDateTime(his.getEndTime()));
        }
        return R.ok().put("data", res);
    }

    /**
     * 历史任务查询（全部）
     *
     * @param processInstanceId 流程实例ID
     */
    @GetMapping("/historyTaskList")
    public R historyTaskList(String processInstanceId) {
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery() // 创建历史活动实例查询
                .processInstanceId(processInstanceId) // 流程实例ID
                .orderByTaskCreateTime()
                .asc()
                .list();


        List res = new ArrayList();
        for (HistoricTaskInstance his : list) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("任务ID:", his.getId());
            map.put("流程实例ID:", his.getProcessInstanceId());
            map.put("任务名称：", his.getName());
            map.put("办理人：", his.getAssignee());
            map.put("开始时间：", DateUtil.formatDateTime(his.getStartTime()));
            map.put("结束时间：", DateUtil.formatDateTime(his.getEndTime()));
            res.add(map);
        }
        return R.ok().put("data", res);
    }

    /**
     * 历史活动查询
     *
     * @param processInstanceId 流程实例ID
     */
    @GetMapping("/history")
    public R historyActInstanceList(String processInstanceId) {
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery() // 创建历史活动实例查询
                .processInstanceId(processInstanceId) // 流程实例ID
                .finished()
                .orderByHistoricActivityInstanceStartTime()
                .asc()
                .list();

        List<Map<String, Object>> res = new ArrayList<>();
        for (HistoricActivityInstance hai : list) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("活动ID:", hai.getId());
            map.put("执行对象ID:", hai.getExecutionId());
            map.put("流程实例ID:", hai.getProcessInstanceId());
            map.put("活动名称：", hai.getActivityName());
            map.put("办理人：", hai.getAssignee());
            map.put("开始时间：", DateUtil.formatDateTime(hai.getStartTime()));
            map.put("结束时间：", DateUtil.formatDateTime(hai.getEndTime()));
            res.add(map);
        }
        return R.ok().put("data", res);
    }

    /**
     * 查看实例流程图，根据流程实例ID获取流程图
     */
    @RequestMapping(value = "traceprocess/{instanceId}")
    public void traceprocess(HttpServletResponse response, @PathVariable("instanceId") String instanceId) throws Exception {
        InputStream in = flowUtils.getResourceDiagramInputStream(instanceId);
        ServletOutputStream output = response.getOutputStream();
        IoUtil.copy(in, output);
    }

}
